home *** CD-ROM | disk | FTP | other *** search
-
- package sub_arctic.lib;
-
- import sub_arctic.input.*;
- import sub_arctic.output.*;
- import sub_arctic.constraints.std_function;
-
- /**
- * Class to allow a subtree to be scrolled in both x and y (i.e., "panned"
- * over).<p>
- *
- * Panner works as a composite object. This is the tree built by the panner.<p>
- *
- *<pre>
- * 0
- * / \
- * / \
- * 1 5
- * / \
- * / \
- * 3 2
- * |
- * 4
- *</pre>
- *
- * Object above are inserted into parents in ascending order (not left to
- * right in the diagram).<p>
- *
- * #3 & #5 are only visible when necessary by the sizing.
- * (these used to be actually removed, we now just change their visibility).<p>
- *
- * #2 and #3 are in that order due to the trickiness with FILL
- * requiring a prev sibling -> next sibling FILL (this is not required with the
- * new constraint system, but we don't fix what ain't broke...). <p>
- *
- * 0 panner no size, you set the size and position. This exports the
- * setting of the horizontal scrollbar as part_a and the
- * vertical as part_b.<p>
- * 1 parent_with_parts (x=0, y=0, h=MINUS_OFFSET(PARENT.RIGHT),
- * w=FILL(PREVIOUS_SIBLING.LEFT)
- * This is child(0) of the panner and is constrained to
- * transmits the setting of the horizontal scrollbar up as
- * its part_a.<p>
- *
- * 2 panner_helper (x=0, y=0, fits around child exactly.<p>
- *
- * 3 h_scrollbar (x=0, y=FAR_EDGE_JUST(PARENT.BOTTOM),
- * w=MINUS_OFFSET(PARENT.RIGHT)<p>
- *
- * 4 your interactor<p>
- * 5 v_scrollbar x=FAR_EDGE_JUST(PREV_SIBLING.RIGHT), y=0,
- * h=PLUS_OFFSET(PARENT.BOTTOM).
- * This is child(1) of the panner.<p>
- *
- * Note that from the panner child(0).child(0).child(0) is the
- * object being panned. From the outside, this can be more easily accessed
- * as panned_child().<p>
- *
- * @Author Ian Smith
- */
- public class panner extends parent_with_parts implements callback_object{
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * The object being panned.
- * @return interactor the single child of this object (which roots the
- * subtree being panned).
- */
- public interactor panned_child() {
- return child(0).child(0).child(0);
- }
-
- /**
- * Set the object being panned.
- * @param interactor c The single child of this object (which roots the
- * subtree being panned).
- */
- public void set_panned_child(interactor c) {
- /* reset to zero position*/
- panner_helper ph=(panner_helper)(child(0).child(0));
- ph.set_x(0);
- ph.set_y(0);
-
- /* tell the panner helper what we have done */
- if (ph.num_children()==0) {
- ph.add_child(c);
- } else {
- ph.set_child(0,c);
- }
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** Do we have a visible horizontal scrollbar. */
- protected boolean have_h_slider;
-
- /** Do we have a visible vertical scrollbar. */
- protected boolean have_v_slider;
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** Actual width of the object being panned. */
- protected int _actual_width;
-
- /** Actual height of the object being panned. */
- protected int _actual_height;
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** Our horizontal scrollbar. */
- h_scrollbar h_control_slider;
-
- /** Our vertical scrollbar. */
- v_scrollbar v_control_slider;
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** Variable to keep track of whether or not to force scrollbars.*/
- protected boolean _force_scrollbars;
-
- /**
- * Indicate whether we are forcing scrollbars to appear.
- * @return boolean indicating whether we force scrollbars to appear.
- */
- public boolean force_scrollbars() { return _force_scrollbars;};
-
- /**
- * Set whether we are forcing scrollbars to appear.
- * @param boolean b indicating whether we force scrollbars to appear.
- */
- public void set_force_scrollbars(boolean b) { _force_scrollbars=b;};
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * This is where we do the magic with scrollbars (deciding visibility, etc.).
- * @param int w new width of panned object.
- * @param int h new height of panned object.
- */
- protected void new_child_size(int w, int h) {
- base_parent_interactor bpi=(base_parent_interactor)child(0).child(0);
-
- /* copy these in */
- _actual_height=h;
- _actual_width=w;
-
- /* take care of the force scrollbars */
- if (_force_scrollbars) {
- add_v_slider();
- add_h_slider();
- set_sbar_values();
- return;
- }
-
- /* ok, lets get rid of the simple case */
- if ((_actual_height<=h()) && (_actual_width<=w())) {
-
- /* we know we don't need EITHER scrollbar */
- /* if we have either of them, remove it */
- if (have_h_slider) {
- h_control_slider.set_visible(false);
- h_control_slider.set_value(0);
- have_h_slider=false;
- bpi.set_x(0);
- }
-
- if (have_v_slider) {
- v_control_slider.set_visible(false);
- v_control_slider.set_value(0);
- have_v_slider=false;
- bpi.set_y(0);
- }
-
- return;
- }
-
- /* do we need v scrollbar? There are two reasons we might:
- 1) _actual_height > h()
- 2) _actual_width > w() &&
- (_actual_height + _h_control_slider.h()) > h() */
-
- /* lets do the simple case first */
- if (_actual_height > h()) {
- /* we are now needing to add one ... assuming we don't have
- one already */
- if (have_v_slider==false) {
- add_v_slider();
- }
- } else {
- /* this is the *easy* removal case ... if it turns out we
- are going to need this scrollbar for the complex reason
- below, we end up adding it back... not very great, but
- it will work */
- if (have_v_slider==true) {
- /* remove the sucker */
- v_control_slider.set_visible(false);
- v_control_slider.set_value(0);
- have_v_slider=false;
- bpi.set_y(0);
- }
- }
-
- /* do we need an h scrollbar in the simple case? */
- if (_actual_width > w()) {
- /* do we already have an sbar */
- if (have_h_slider==false) {
- add_h_slider();
- }
- } else {
- /* again, this is the simple removal case... we may end up
- adding it back again later */
- if (have_h_slider==true) {
- h_control_slider.set_visible(false);
- h_control_slider.set_value(0);
- have_h_slider=false;
- bpi.set_x(0);
- }
- }
-
- /* at this point we know somebody has to need a scrollbar,
- and we also know that the simple removal cases are covered, so
- at least one of have_h_slider & have_v_slider is true ...
- in either case if the other one is false, we need to check
- for the complex case and add a scrollbar if necessary */
- if ((have_h_slider==true) && (have_v_slider==false)) {
- if (_actual_height + h_control_slider.h() > h()) {
- /* need to add it any way */
- add_v_slider();
- }
- }
-
- /* this is the other complex case */
- if ((have_v_slider==true) && (have_h_slider==false)) {
- if (_actual_width + v_control_slider.w() > w()) {
- /* add it due to complex case */
- add_h_slider();
- }
- }
-
- /* now set values */
- set_sbar_values();
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * This code makes the horizontal slider visible. It doesn't try to
- * put in the right maximum value, this is done in set_sbar_values().
- */
- protected void add_h_slider() {
-
- /* make it visible */
- have_h_slider=true;
- h_control_slider.set_visible(true);
- h_control_slider.set_value(0);
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * This code make the horizontal slider visible. It doesn't try to
- * put in the right maximum value, this is done in set_sbar_values().
- */
- protected void add_v_slider() {
-
- /* make it visible and reset its value */
- have_v_slider=true;
- v_control_slider.set_visible(true);
- v_control_slider.set_value(0);
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** This sets the scrollbar values such as max value. */
- protected void set_sbar_values() {
-
- /* set the values ... vertical first*/
- if (have_v_slider) {
-
- /* if we have an h slider compensate */
- if (have_h_slider) {
- v_control_slider.set_max_val(_actual_height-
- (h()-(h_control_slider.h())));
- v_control_slider.
- set_thumb_percentage(((double)h()-(double)h_control_slider.h())/
- ((double)_actual_height));
- } else {
- /* simple case, just figure out how much of a pan we need */
- v_control_slider.set_max_val(_actual_height-h());
- v_control_slider.
- set_thumb_percentage(((double)h())/((double)_actual_height));
- }
- // set increments to be a little less than a screenfull
- v_control_slider.set_large_inc(h()-v_control_slider.small_inc());
- }
-
- /* now set the horiz value */
- if (have_h_slider) {
- /* compensate for possible v slider */
- if (have_v_slider) {
-
- h_control_slider.set_max_val(_actual_width-
- (w()-(v_control_slider.w())));
- h_control_slider.
- set_thumb_percentage(((double)w()-(double)v_control_slider.w())/
- ((double)_actual_width));
- } else {
-
- /* simple case horizontally */
- h_control_slider.set_max_val(_actual_width-w());
- h_control_slider.
- set_thumb_percentage(((double)w())/((double)_actual_width));
- }
- // set increments to be a little less than a screenfull
- h_control_slider.set_large_inc(w()-h_control_slider.small_inc());
- }
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Handle the fact that child's size changed in y.
- * @param int newvalue new size value.
- */
- protected void child_size_changed_h(int newvalue) {
- new_child_size(panned_child().w(),newvalue);
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Handle the fact that child's size changed in x.
- * @param int newvalue new size value.
- */
- protected void child_size_changed_w(int newvalue) {
- new_child_size(newvalue,panned_child().h());
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Create a new panner which pans over the given child.
- * We assume you will set the w, h, and x,y with constraints.
- *
- * @param base_interactor chld the root of the subtree we are panning over.
- */
- public panner(base_interactor chld) {
- super(0,0);
-
- parent_with_parts bpi;
- panner_helper ph;
-
- /* put the parent and panner_helper */
- bpi=new parent_with_parts(0,0);
- bpi.set_h_constraint(std_function.offset(PARENT.Y2(), 0));
- bpi.set_w_constraint(std_function.fill(PREV_SIBLING.X(), NEXT_SIBLING.X(), 0));
- add_child(bpi);
-
- ph=new panner_helper();
- ph.set_x(0);
- ph.set_y(0);
- ph.set_w_constraint(std_function.offset(FIRST_CHILD.X2(),0));
- ph.set_h_constraint(std_function.offset(FIRST_CHILD.Y2(),0));
- bpi.add_child(ph);
-
- /* put the scrollbars in place */
- h_control_slider=new h_scrollbar(this);
- h_control_slider.set_x(0);
- h_control_slider.set_y_constraint(std_function.far_edge_just(PARENT.Y2(),0));
- h_control_slider. set_w_constraint(std_function.offset(PARENT.X2(),0));
- child(0).set_child(1,h_control_slider);
-
- v_control_slider=new v_scrollbar(this);
- v_control_slider.set_x_constraint(std_function.far_edge_just(PARENT.X2(), 0));
- v_control_slider.set_y(0);
- v_control_slider.set_h_constraint(std_function.offset(PARENT.Y2(), 0));
- set_child(1,v_control_slider);
-
- // set increments to be a little less than a screenfull
- h_control_slider.set_large_inc(w()-h_control_slider.small_inc());
- v_control_slider.set_large_inc(h()-v_control_slider.small_inc());
-
- /* initially we don't have visible scrollbars */
- have_h_slider=have_v_slider=false;
- h_control_slider.set_visible(false);
- v_control_slider.set_visible(false);
-
- /* set constraints to copy out the settings of the scrollbars */
- bpi.set_part_a_constraint(std_function.eq(LAST_CHILD.PART_A()));
- set_part_a_constraint(std_function.eq(FIRST_CHILD.PART_A()));
- set_part_b_constraint(std_function.eq(LAST_CHILD.PART_A()));
-
- /* setup things for this new panned child */
- set_panned_child(chld);
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Callback routine that receives callbacks from the scrollbars.
- *
- * @param interactor from_obj the interactor the callback is from.
- * @param event evt the event "causing" the callback.
- * @param int callback_num the number of the callback (indicating
- * what kind).
- * @param Object callback_info parameter information associated with the
- * callback.
- */
- public void callback(interactor from_obj,
- event evt,
- int callback_num,
- Object callback_info)
- {
- Integer value=(Integer)callback_info;
- int v=value.intValue();
- base_parent_interactor bpi;
-
- /* we don't want anything except real time! ignore static callback */
- if (callback_num == h_slider.STATIC_CALLBACK) return;
-
- /* get the object we move around */
- bpi=(base_parent_interactor)child(0).child(0);
-
- /* horizontal move */
- if (from_obj == h_control_slider) {
- bpi.set_x(-v);
- } else {
- /* vertical move */
- bpi.set_y(-v);
- }
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Catch our resizes so we can change scrollbars, etc.
- * @param int v new h value.
- */
- protected void set_raw_h(int v) {
- super.set_raw_h(v);
- /* recompute the values for sbars and whatnot*/
- new_child_size(panned_child().w(), panned_child().h());
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Catch our resizes so we can change scrollbars, etc.
- * @param int v new w value.
- */
- protected void set_raw_w(int v) {
- super.set_raw_w(v);
- /* recompute the values for sbars and whatnot*/
- new_child_size(panned_child().w(), panned_child().h());
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
- /**
- * This function is used to control X coordinate of the point which
- * the upper left corner of the panner is viewing.
- * @param int x the x coordinate of the top left corner of the panner
- * with respect to the panned object
- */
- public void set_x_view_coordinate(int x) {
- base_parent_interactor bpi;
-
- bpi=(base_parent_interactor)child(0).child(0);
-
- /* validity check */
- if (x<h_control_slider.min_val()) {
- x=h_control_slider.min_val();
- }
- if (x>h_control_slider.max_val()) {
- x=h_control_slider.max_val();
- }
- /* its in the range, just set the slider */
- h_control_slider.set_value(x);
- /* move the panner's display */
-
- bpi.set_x(-x);
- }
- /**
- * This function is used to control Y coordinate of the point which
- * the upper left corner of the panner is viewing.
- * @param int y the y coordinate of the top left corner of the panner
- * with respect to the panned object
- */
- public void set_y_view_coordinate(int y) {
- base_parent_interactor bpi;
-
- bpi=(base_parent_interactor)child(0).child(0);
-
- /* validity check */
- if (y<v_control_slider.min_val()) {
- y=v_control_slider.min_val();
- }
- if (y>v_control_slider.max_val()) {
- y=v_control_slider.max_val();
- }
- /* its in the range, just set the slider */
- v_control_slider.set_value(y);
- /* move the panner's display */
-
- bpi.set_y(-y);
- }
- }
-
- /*=========================== COPYRIGHT NOTICE ===========================
-
- This file is part of the subArctic user interface toolkit.
-
- Copyright (c) 1996 Scott Hudson and Ian Smith
- All rights reserved.
-
- The subArctic system is freely available for most uses under the terms
- and conditions described in
- http://www.cc.gatech.edu/gvu/ui/sub_arctic/sub_arctic/doc/usage.html
- and appearing in full in the lib/interactor.java source file.
-
- The current release and additional information about this software can be
- found starting at: http://www.cc.gatech.edu/gvu/ui/sub_arctic/
-
- ========================================================================*/
-